會想寫這一篇是因為其實官網的tutorial或是現在買得到的書,網站裡面,很少提到如何在elm裡做http post
這個動作。而相關的文章、套件也相當少。不只是這個,譬如要上傳檔案或是animation。甚至要讀取localStorage等等都還是缺乏相關套件,還是要使用外部的javascript去port進來。所以找了一些資料,自己拼拼湊湊出一個樣子。雖然 Http
套件裡有文檔說明,但沒有完整的使用。
ellie 上的範例檔。這是在 stackoverflow上面,有人問到如何submitform,無論是submit form,或是login/logout/signin等等,都是做一個http request/response的http post的動作。elm裡的http 套件裡,也有一個 Http.post
。
post : String -> Body -> Decoder a -> Request a
import Http
import Json.Decode exposing (list, string)
postBooks : Http.Request (List String)
postBooks =
Http.post "https://example.com/books" Http.emptyBody (list string)
postComment newComment =
Http.send AddCommentHttp
(Http.post "https://jsonplaceholder.typicode.com/posts"
(encodeNewComment newComment)
decodeComment
)
encodeNewComment : NewComment -> Http.Body
encodeNewComment newComment =
Http.jsonBody <|
Json.Encode.object
[ ( "title", Json.Encode.string newComment.title )
, ( "body", Json.Encode.string newComment.body )
, ( "userId", Json.Encode.int newComment.userId )
]
在這個例子我們可以清楚看到,我們 post到某個網站後,http body 是一個jsonBody:
jsonBody : Value -> Body
Put some JSON value in the body of your Request. This will automatically add the Content-Type: application/json header.
等得到訊息後(http response),我們就可以用decode來處理,處理完後,用 Http.send
把這個訊息寄出去給 elm runtime
讓 update
知道我們下一步要做什麼。
如果是login/logout,你得到的response會有一個session,你要存在localStorage裡,所以要和外界的javascript互動,而且你每次send to server的 東西,都要有這個session。其實到這裡就是一些基本的http
response/request的常識了。如果看不懂,可以要回去惡補一下,因為Elm是前端的東西,如果和後端去溝通,elm裡沒有幫你處理,但有提供相關的套件,以下是localStorage如何互動的範例
...
var storedState = localStorage.getItem('model');
var startingState = storedState ? JSON.parse(storedState) : null;
var elmApp = Elm.Main.fullscreen(startingState);
elmApp.ports.setStorage.subscribe(function(state) {
localStorage.setItem('model', JSON.stringify(state));
});
elmApp.ports.removeStorage.subscribe(function() {
localStorage.removeItem('model');
});
...
-- Helper to update model and set localStorage with the updated model
setStorageHelper : Model -> ( Model, Cmd Msg )
setStorageHelper model =
( model, setStorage model )
-- Messages
...
-- Ports
port setStorage : Model -> Cmd msg
port removeStorage : Model -> Cmd msg
-- Update
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
...
GetTokenSuccess newToken ->
setStorageHelper { model | token = newToken, password = "", errorMsg = "" }
...
FetchProtectedQuoteSuccess newPQuote ->
setStorageHelper { model | protectedQuote = newPQuote }
LogOut ->
( { model | username = "", password = "", protectedQuote = "", token = "", errorMsg = "" },
這兩個就是我說的用Http.post,不過因為是Elm 0.17的文章了。有些符號有改變,譬如 Json.Decode裡的 (:=)
就是我們之前說的 field
而裡面用的Task方法,在0.18也有改變;有些方式也可以用 Http.post
來取代。0.18也出來一年多了,但是官方版的tutorial 一直沒有把 Task
的教學在放回來;或是如何post也沒有多做說明。像是之前提到navigation/routing,官方的roadmap也是寫到下一版0.19也會做改進。總之,因為elm目前還在發展,加上社群相對小,仍然有一些功能待開發(但也都可以找到替代方案。)之後幾篇再來談談和elm相似的前端處理框架。